

using System;
using System.Xml;

namespace Nutils
{
    public class Exception : System.Exception
    {
        public Exception(string sMsg)
            : base(sMsg)
        {
        }
    }

    public class FileTypeMap
    {
        private System.Collections.ArrayList _associations;
        private static FileTypeMap _singleton;

        public FileTypeMap()
        {
            _associations = new System.Collections.ArrayList();
        }

        public static FileTypeMap Instance()
        {
            if (null == _singleton)
            {
                _singleton = new FileTypeMap();
            }
            return _singleton;
        }

        public System.Text.Encoding Find( string filename, System.Text.Encoding failover)
        {
            string filename_lowered = filename.ToLower();
            foreach (Association cur in _associations)
            {
                if (_Match(cur, filename_lowered))
                {
                    return cur.encoding;
                }
            }

            return failover;
        }
        
        public void Add( string ext, string dir, System.Text.Encoding enconding)
        {
            _associations.Add(new Association(ext, dir, System.Text.Encoding.ASCII));
        }

        private bool _Match(Association check, string filename)
        {
            string dir = System.IO.Path.GetPathRoot(filename);
            string ext = System.IO.Path.GetExtension(filename);

            if( check.extension.Length > 0 && check.directory.Length > 0 ) 
            {
                return ext.Equals(check.extension) && dir.Contains(check.directory);
            }

            if (check.extension.Length > 0)
            {
                return ext.Equals(check.extension);
            }

            if (check.directory.Length > 0)
            {
                return dir.Contains(check.directory);
            }

            //none
            return false;
        }

        private struct Association
        {
            readonly public string extension;
            readonly public string directory;
            readonly public System.Text.Encoding encoding;

            public Association(string extension, string directory, System.Text.Encoding encoding)
            {
                this.extension = extension.ToLower();
                this.directory = directory.ToLower();
                this.encoding = encoding;
            }
        }
    }

    public static class Hack
    {
        public static void CheckFileLock(string fileName)
        {
            Nutils.Console.Spam("CheckFileLock: " + fileName);
            while (true)
            {
                try
                {
                    _CheckFileLock(fileName);
                    return;
                }
                catch (System.IO.IOException)
                {
                    System.Threading.Thread.Sleep(1);
                    Nutils.Console.Spam("Failed CheckFileLock: " + fileName);
                }
            }
        }

        private static void _CheckFileLock(string fileName)
        {
            if (!System.IO.File.Exists(fileName))
            {
                return;
            }

            System.IO.StreamWriter txtw = new System.IO.StreamWriter(fileName,true);
            txtw.Close();
        }
    }

    public static class Crypto
    {
        //const string _Hash = @"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()-_=+[]{}|:;<>,.? ";
        const string _Hash = @"l26bKz&A)7fn*v=|mCiI-QJ!:LXBSNc?Doq[E%PW+Z <@{(tRMwg4TVG$j;1dHk]#_a0^xre9}Us8pF5h>,.uyOY3";
        public static string Encrypt(string val, int key)
        {
            int n = 0;
            string sResult = "";
            foreach (char c in val)
            {
                sResult += _Hash[(_Hash.IndexOf(c) + key + n) % _Hash.Length];
                ++n;
            }

            return sResult;
        }
        public static string Decrypt(string val, int key)
        {
            int n = 0;
            string sResult = "";
            foreach (char c in val)
            {
                int i = (_Hash.IndexOf(c) - key - n);
                if (i < 0)
                {
                    i += _Hash.Length;
                }
                sResult += _Hash[i];
                ++n;
            }

            return sResult;
        }

    }

    public static class XML
    {
        public class Writer : System.Xml.XmlTextWriter { public Writer(string FilePath) : base(FilePath, System.Text.Encoding.Unicode) { } }
        public class Reader : System.Xml.XmlTextReader { public Reader(string FilePath) : base(FilePath) { } }

        public static XML.Writer OpenWriter(string XmlFilePath)
        {
            try
            {
                return new XML.Writer(XmlFilePath);
            }
            catch (System.Exception ex)
            {
                Nutils.Console.Error("Failed to open '" + XmlFilePath + "' for writing.");
                Nutils.Console.Error(ex.Message);
                return null;
            }
        }

        public static XML.Reader OpenReader(string XmlFilePath)
        {
            try
            {
                return new XML.Reader(XmlFilePath);
            }
            catch (System.Exception ex)
            {
                Nutils.Console.Error("Failed to open '" + XmlFilePath + "' for reading.");
                Nutils.Console.Error(ex.Message);
                return null;
            }
        }

        public static XML.Writer OpenWriter_WaitTillUnlocked(string XmlFilePath)
        {
            Hack.CheckFileLock(XmlFilePath);
            return XML.OpenWriter(XmlFilePath);
        }
    }
}
